package com.yjzx.util.common.util.number;

/**
 * @author yjzx
 * @create 2023/3/8
 * @Description
 */
public class BytesRadixUtils {

    /**
     * 数字转为16进制字符串
     * @param val 要转换的数字
     * @param spilt 是否分段显示
     * @return
     */
    public static String toHexString(long val, boolean spilt) {
        return formatUnsignedBytes(ByteUtils.numberToBytes(val, 8), (byte) 4, spilt);
    }
    /**
     * 数字转为8进制字符串
     * @param val 要转换的数字
     * @param spilt 是否分段显示
     * @return
     */
    public static String toOctalString(long val, boolean spilt) {

        return formatUnsignedBytes(ByteUtils.numberToBytes(val, 8), (byte) 3, spilt);
    }

    /**
     * 数字转为二进制字符串
     * @param val 要转换的数字
     * @param spilt 是否分段显示
     * @return
     */
    public static String toBinaryString(long val, boolean spilt) {
        return formatUnsignedBytes(ByteUtils.numberToBytes(val, 8), (byte) 1, spilt);
    }

    final static char[] digits = {
            '0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'a', 'b',
            'c', 'd', 'e', 'f', 'g', 'h',
            'i', 'j', 'k', 'l', 'm', 'n',
            'o', 'p', 'q', 'r', 's', 't',
            'u', 'v', 'w', 'x', 'y', 'z'
    };

    /**
     * bytes转换为指定进制字符串
     *
     * @param val   字节数组
     * @param shift 几比特转换
     * @return
     */
    public static String formatUnsignedBytes(byte[] val, byte shift) {
        //bit长度
        int len = val.length << 3;
        //字符长度
        int bufLength = len % shift != 0 ? len / shift + 1 : len / shift;
        char[] buf = new char[bufLength];
        //未使用长度
        int charPos = bufLength;
        int valIndex = val.length - 1;
        //
        byte radix = (byte) (1 << shift);
        byte mask = (byte) (radix - 1);
        //控制byte值
        int control = 0xFF & val[valIndex];
        //当前byte值未使用长度
        int byteLen = 8;
        do {
            buf[--charPos] = digits[(control) & mask];
            byteLen -= shift;
            control >>>= shift;
            if (byteLen < shift && valIndex >= 1) {
                valIndex--;
                control |= ((0xFF & val[valIndex]) << byteLen);
                byteLen += 8;
            }
        } while (charPos > 0);
        return new String(buf, charPos, (bufLength - charPos));
    }
    /**
     * bytes转换为指定进制字符串
     *
     * @param val   字节数组
     * @param shift 几比特转换
     * @param spilt 是否分段显示
     * @return
     */
    public static String formatUnsignedBytes(byte[] val, byte shift, boolean spilt) {
        if (spilt) {
            int len = val.length << 3;
            int bufLength = len % shift != 0 ? len / shift + 1 : len / shift;
            int split = Integer.MAX_VALUE;
            if ((shift == 1 || shift == 3 || shift == 4)) {
                bufLength = bufLength +
                        (shift == 1 ? (bufLength >> 3) - 1 :
                                shift == 4 ? (bufLength >> 2) - 1 :
                                        bufLength % 3 == 0 ? bufLength / 3 - 1 : bufLength / 3);
                split = shift == 1 ? 9 : shift == 4 ? 5 : 4;
            }
            char[] buf = new char[bufLength];
            int charPos = bufLength;
            int charPos2 = charPos;

            byte radix = (byte) (1 << shift);
            int valIndex = val.length - 1;
            byte mask = (byte) (radix - 1);
            int a = 0xFF & val[valIndex];
            int b = 8;
            int n = 1;
            do {
                if (n % split == 0) {
                    buf[--charPos] = '_';
                    n++;
                }
                buf[--charPos] = digits[(a) & mask];
                b -= shift;
                a >>>= shift;

                if (b < shift && valIndex >= 1) {
                    valIndex--;
                    a |= ((0xFF & val[valIndex]) << b);
                    b += 8;
                }
                n++;
            } while (charPos > 0);
            return new String(buf, charPos, (charPos2 - charPos));
        }else {
            return formatUnsignedBytes(val, shift);
        }
    }

    /**
     * 16进制字符串转为byte数组,字符串长度应该为2的倍数否则会丢失最后一个
     *
     * @param hexString 16进制字符串
     * @return byte数组，大小为字符串长度的一半
     */
    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || "".equals(hexString)) {
            return null;
        }
        hexString = hexString.toUpperCase();
        if (hexString.length() % 2 != 0) {
            hexString = '0' + hexString;
        }
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] bytes = new byte[length];
        for (int i = length - 1; i >= 0; i--) {
            int pos = i * 2;
            bytes[i] = (byte) (ByteUtils.charToByte(hexChars[pos]) << 4 | ByteUtils.charToByte(hexChars[pos + 1]));
        }
        return bytes;
    }

    /**
     * byte数组转为16进制字符串
     *
     * @param bytes byte数组
     * @return 16进制字符串，长度为数组大小的两倍
     */
    public static String bytesToHexString(byte[] bytes) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        byte len = 4;
        for (int length = bytes.length; length > 0; length -= len) {
            stringBuilder.append(formatUnsignedBytes(bytes, (byte) 4));
        }
        return stringBuilder.toString();
    }

    /**
     * 从参数字节数组中获取指定长度的字节数组转成16进制字符串
     *
     * @param src    字节数组
     * @param offset 偏移量
     * @param len    指定的长度
     * @return 16进制字符串
     */
    public static String bytesToHexString(byte[] src, int offset, int len) {
        byte[] bytes = ByteUtils.getBytesForLen(src, offset, len);
        return bytesToHexString(bytes);
    }

    /**
     * byte数组转为2进制字符串
     *
     * @param bytes byte数组
     * @return 2进制字符串
     */
    public static String bytesToBinaryString(byte[] bytes) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        byte len = 4;
        for (int length = bytes.length; length > 0; length -= len) {
            stringBuilder.append(formatUnsignedBytes(bytes, (byte) 1));
        }
        return stringBuilder.toString();
    }

    /**
     * 从参数字节数组中获取指定长度的字节数组转成2进制字符串
     *
     * @param src    字节数组
     * @param offset 偏移量
     * @param len    指定的长度
     * @return 2进制字符串
     */
    public static String bytesToBinaryString(byte[] src, int offset, int len) {
        byte[] bytes = ByteUtils.getBytesForLen(src, offset, len);
        return bytesToBinaryString(bytes);
    }



}
